package com.amt.filter;

import com.alibaba.fastjson.JSON;
import com.amt.configure.Secret;
import com.amt.configure.SpringBean;
import com.amt.util.MD5Util;
import com.amt.util.RedisTemplateUtil;
import com.amt.util.StringUtil;
import com.amt.util.TokenUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.DatatypeConverter;
import java.io.IOException;

/**
 * @Title: AuthFilter.java
 * @Package com.amt.filter
 * @Description: TODO(权限过滤器)
 * @author 江伟
 * @date 2021年3月月11日 下午4:42:06
 * Copyright (c) ©1994-2021 Scjydz.com All Rights Reserved.
 */
@Slf4j
public class AuthFilter extends HandlerInterceptorAdapter {

	private static AntPathMatcher antPathMatcher = new AntPathMatcher();
	// 请求白名单
    private static final String[] ignoreUrls = {
			"/gpzfb/user/mini/auth/authorize",
			"/gpzfb/user/mini/auth/aecToken",
            "/gpzfb/user/mini/auth/getAccessToken",
            "/gpzfb/pay/ali/order/payBack",
            "/gpzfb/pay/ali/order/payBackInsurance",
            "/gpzfb/outpatient/mineReg/getUserOrderInfo",
            "/gpzfb/user/backstage/auth/login",
            "/gpzfb/user/backstage/menu/listTreeSystemMenu",
            "/gpzfb/test/getDoctors",
            "/gpzfb/test/getOutDept",
            "/gpzfb/test/getDeptList",
			"/gpzfb/pay/ali/order/refundOpen",
            "gpzfb/outPatient/mini/payment/myTest",
			"/gpzfb/pay/ali/order/refundInsurance"


    };

	// 重复访问黑名单
	private static final String[] repeatUrls = {
			"/gpzfb/outpatient/wechat/reg/todayPlaceAnOrder",
			"/gpzfb/outpatient/wechat/reg/subscribePlaceAnOrderNew",
			"/gpzfb/outpatient/wechat/reg/wechatPlaceOrder"

	};


	/**
	 * 权限处理
	 * @throws IOException
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
		if (!(handler instanceof HandlerMethod)) {
			return true;
		}
		// 过滤请求白名单
		boolean check = true;
		for (String item : ignoreUrls) {
			if (antPathMatcher.match(item, request.getRequestURI())) {
				check = false;
				break;
			}
		}
		String userid = null;
		if(check) {
			String accessToken = request.getHeader("accessToken");
			if (StringUtil.isEmpty(accessToken)) {
				log.error("非法访问，权限码为空！");
				response.setStatus(401);
				response.getWriter().write("{\"status\":401,\"message\":\"accessToken is empty!\"}");
				return false;
			}
//			 if ("lczfb666888".equals(accessToken)) {
//			 	return true;
//			 }
			TokenUtil tokenUtil = SpringBean.getBean(TokenUtil.class);
			// 验证accessToken合法性
			String result = tokenUtil.checkToken(accessToken);
			if (!"ok".equals(result)) {
				response.setStatus(401);
				response.getWriter().write("{\"status\":401,\"message\":\""+result+"!\"}");
				return false;
			}


			Secret secret =  SpringBean.getBean(Secret.class);
			Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(secret.getKey()+"qjyxcb")).parseClaimsJws(accessToken).getBody();
			if(null == claims.getId()) {
				response.setStatus(401);
				response.getWriter().write("{\"status\":401,\"message\":\"accessToken is error!\"}");
				return false;
			}
			RedisTemplateUtil redisTemplateUtil = SpringBean.getBean(RedisTemplateUtil.class);
			boolean flag = false;
			for (String item : repeatUrls) {
				if (antPathMatcher.match(item, request.getRequestURI())) {
					flag = true;
					break;
				}
			}
			if(flag) {
				// 重复提交验证
		        String key = MD5Util.md5(accessToken + "-" + request.getRequestURL().toString()+"-"+ JSON.toJSONString(request.getParameterMap()), "666888");
//		        log.info("getRequestURL:{},getParameterMap:{},请求路径key:{}",request.getRequestURL().toString(),JSON.toJSONString(request.getParameterMap()),key);
		        if (StringUtil.isEmpty(redisTemplateUtil.get(key, String.class))) {
	                // 默认1秒内统一用户同一个地址同一个参数，视为重复提交
	            	redisTemplateUtil.set(key, "0", 1);
		        } else {
		        	response.setStatus(202);
		        	response.getWriter().write("{\"status\":202,\"message\":\"request rating too fast!\"}");
		        	return false;
		        }
			}
			userid = claims.getId();
			String userKey = "user"+userid;
			// 清除登录用户accessToken
			if ("/gpzfb/user/backstage/auth/logOut".equals(request.getRequestURI())) {
				redisTemplateUtil.del(userKey);
	        	return true;
	        }
			//log.info("userId:{}",userid);
			// 用来验证后台系统用户不能重复登录（过滤前端账户）
			if (userid.indexOf("zfbsys") == 0 && !userid.equals("zfbsys4")) {
				boolean hasToken = redisTemplateUtil.hasKey(userKey);
				if (hasToken && redisTemplateUtil.getExpire(userKey) > 0) {
					String userToken = redisTemplateUtil.get(userKey, String.class);
					log.info("userToken:",userToken);
					// 后台登录刷新缓存
					if (!StringUtils.isEmpty(userToken)
							&& "/gpzfb/user/backstage/auth/info".equals(request.getRequestURI())) {
						redisTemplateUtil.set(userKey, accessToken, 14300);
					} else if (!StringUtils.isEmpty(userToken) && !userToken.equals(accessToken)) {
						redisTemplateUtil.del(userKey);
						response.setStatus(403);
						response.getWriter().write("{\"status\":403,\"message\":\"account login in other places, please login again!\"}");
						return false;
					}
				} else {
					// 设置用户token，默认3.97小时
					redisTemplateUtil.set(userKey, accessToken, 14300);
				}

			}

		}
		return true;
	}

}
